#if !defined(AFX_BUFFER_H__9609847C_A2BB_42B8_9D1E_27660D90EF57__INCLUDED_)
#define AFX_BUFFER_H__9609847C_A2BB_42B8_9D1E_27660D90EF57__INCLUDED_

#pragma warning(disable:4786)

#include <string.h>
#include <string>
#include <map>
#include <list>
#include <vector>
#include <set>
#include <stdio.h>

#if _MSC_VER > 1000
    #pragma once
#endif

class CBuffer
{
public:
    inline CBuffer(int nSize)
    {
        m_bDelete = true;
        m_nIndex = 0;
        m_nSize = nSize;
        m_pBuf = new char[nSize];
    };
    inline CBuffer(const void *pData, int nSize)
    {
        m_bDelete = false;
        m_nIndex = 0;
        m_nSize = nSize;
        m_pBuf = (char *)pData;
    };
    inline virtual ~CBuffer()
    {
        if (m_bDelete && m_pBuf != NULL)
        {
            delete m_pBuf;
        }
    };
    inline int WriteFile(const char *lpszFile);
    inline int ReadFile(const char *lpszFile);

    inline void Reset()
    {
        if (m_nIndex > 0)
        {
            m_nSize = m_nIndex;
        }
        m_nIndex = 0;
    };
    inline operator const char *() const
    {
        return m_pBuf;
    };
    inline const char *Data() const
    {
        return m_pBuf;
    };
    inline const int Size() const
    {
        return m_nIndex;
    };
    inline void	Dump();

    inline CBuffer &Write(void *pBuf, int nLength);
    inline CBuffer &Read(void *pBuf, int &nLength);
    inline CBuffer &Read2(void *&pBuf, int &nLength);

    inline CBuffer &operator << (const bool nT);
    inline CBuffer &operator >> (bool &nT);
    inline CBuffer &operator << (const char nT);
    inline CBuffer &operator >> (char &nT);
    inline CBuffer &operator << (const unsigned char nT);
    inline CBuffer &operator >> (unsigned char &nT);
    inline CBuffer &operator << (const short nT);
    inline CBuffer &operator >> (short &nT);
    inline CBuffer &operator << (const unsigned short nT);
    inline CBuffer &operator >> (unsigned short &nT);
    inline CBuffer &operator << (const int nT);
    inline CBuffer &operator >> (int &nT);
    inline CBuffer &operator << (const unsigned int nT);
    inline CBuffer &operator >> (unsigned int &nT);
    inline CBuffer &operator << (const long nT);
    inline CBuffer &operator >> (long &nT);
    inline CBuffer &operator << (const unsigned long nT);
    inline CBuffer &operator >> (unsigned long &nT);
    inline CBuffer &operator << (const long long nT);
    inline CBuffer &operator >> (long long &nT);
    inline CBuffer &operator << (const unsigned long long nT);
    inline CBuffer &operator >> (unsigned long long &nT);
    inline CBuffer &operator << (const char *pBuf);
    inline CBuffer &operator >> (char *&pBuf);
    inline CBuffer &operator << (const unsigned char *pBuf);
    inline CBuffer &operator >> (unsigned char *&pBuf);
    inline CBuffer &operator << (const float v);
    inline CBuffer &operator >> (float &v);
    inline CBuffer &operator << (const double v);
    inline CBuffer &operator >> (double &v);
    inline CBuffer &operator << (const std::string &v);
    inline CBuffer &operator >> (std::string &v);

    template<typename T> inline CBuffer &operator << (const std::vector<T> &v)
    {
        short nLen = (int)v.size();
        if (nLen > 0)
        {
            *this << nLen;
            typename std::vector<T>::const_iterator it;
            for (it = v.begin(); it != v.end(); it++)
            {
                *this << (T &)*it;
            }
        }
        else
        {
            nLen = 0;
            *this << nLen;
        }

        return *this;
    };

    template<class T> inline CBuffer &operator >> (std::vector<T> &v)
    {
        short nLen = 0;
        *this >> nLen;
        v.clear();
        if (nLen > 0)
        {
            v.reserve(nLen);
            for (int i = 0 ; i < nLen; i++)
            {
                T t;
                *this >> t;
                v.push_back(t);
            }
        }
        return *this;
    };

    template<typename T> inline CBuffer &operator << (const std::list<T> &v)
    {
        short nLen = v.size();
        if (nLen > 0)
        {
            *this << nLen;
            typename std::list<T>::const_iterator it;
            for (it = v.begin(); it != v.end(); it++)
            {
                *this << (T &)*it;
            }
        }
        else
        {
            nLen = 0;
            *this << nLen;
        }

        return *this;
    };

    template<class T> inline CBuffer &operator >> (std::list<T> &v)
    {
        short nLen = 0;
        *this >> nLen;
        v.clear();
        if (nLen > 0)
        {
            for (int i = 0 ; i < nLen; i++)
            {
                T t;
                *this >> t;
                v.push_back(t);
            }
        }
        return *this;
    };

    template<typename T> inline CBuffer &operator << (const std::set<T> &v)
    {
        short nLen = v.size();
        if (nLen > 0)
        {
            *this << nLen;
            typename std::set<T>::const_iterator it;
            for (it = v.begin(); it != v.end(); it++)
            {
                *this << (T &)*it;
            }
        }
        else
        {
            nLen = 0;
            *this << nLen;
        }

        return *this;
    };

    template<class T> inline CBuffer &operator >> (std::set<T> &v)
    {
        short nLen = 0;
        *this >> nLen;
        v.clear();
        if (nLen > 0)
        {
            for (int i = 0 ; i < nLen; i++)
            {
                T t;
                *this >> t;
                v.insert(t);
            }
        }
        return *this;
    };

    template<typename K, typename T> inline CBuffer &operator << (const std::map<K, T> &v)
    {
        short nLen = v.size();
        if (nLen > 0)
        {
            *this << nLen;
            typename std::map<K, T>::const_iterator it;
            for (it = v.begin(); it != v.end(); it++)
            {
                *this << it->first << (T &)it->second;
            }
        }
        else
        {
            nLen = 0;
            *this << nLen;
        }

        return *this;
    };

    template<class K, class T> inline CBuffer &operator >> (std::map<K, T> &v)
    {
        short nLen = 0;
        *this >> nLen;
        v.clear();
        if (nLen > 0)
        {
            for (int i = 0 ; i < nLen; i++)
            {
                K k;
                T t;
                *this >> k >> t;
                v.insert(std::make_pair(k, t));
            }
        }
        return *this;
    };

private:
    bool	m_bDelete;
    int		m_nIndex;
    int		m_nSize;
    char	*m_pBuf;
};

inline CBuffer &CBuffer::Write(void *pBuf, int nLength)
{
    if (pBuf != NULL && nLength > 0 && nLength <= 0xFFFFFF)
    {
        *this << nLength;
        memcpy(m_pBuf + m_nIndex, pBuf, nLength);
        m_nIndex += nLength;
    }
    else
    {
        nLength = 0;
        *this << nLength;
    }
    return *this;
}

inline CBuffer &CBuffer::Read(void *pBuf, int &nLength)
{
    if (nLength == 0)
    {
        *this >> nLength;
    }

    if (pBuf != NULL && nLength > 0 && nLength <= 0xFFFFFF)
    {
        memcpy(pBuf, m_pBuf + m_nIndex, nLength);
        m_nIndex += nLength;
    }
    return *this;
}

inline CBuffer &CBuffer::Read2(void *&pBuf, int &nLength)
{
    if (nLength == 0)
    {
        *this >> nLength;
    }

    if (nLength > 0 && nLength <= 0xFFFFFF)
    {
        if (pBuf == NULL)
        {
            pBuf = new char[nLength];
        }
        memcpy(pBuf, m_pBuf + m_nIndex, nLength);
        m_nIndex += nLength;
    }
    return *this;
}

inline CBuffer &CBuffer::operator << (const bool nT)
{
    m_pBuf[m_nIndex++] = nT;
    return *this;
}

inline CBuffer &CBuffer::operator >> (bool &nT)
{
    nT = (m_pBuf[m_nIndex++] ? true : false);
    return *this;
}

inline CBuffer &CBuffer::operator << (const char nT)
{
    m_pBuf[m_nIndex++] = nT;
    return *this;
}

inline CBuffer &CBuffer::operator >> (char &nT)
{
    nT = m_pBuf[m_nIndex++];
    return *this;
}

inline CBuffer &CBuffer::operator << (unsigned const char nT)
{
    m_pBuf[m_nIndex++] = nT;
    return *this;
}

inline CBuffer &CBuffer::operator >> (unsigned char &nT)
{
    nT = m_pBuf[m_nIndex++];
    return *this;
}

inline CBuffer &CBuffer::operator << (const short nT)
{
    memcpy(m_pBuf + m_nIndex, &nT, 2);
    m_nIndex += 2;
    return *this;
}

inline CBuffer &CBuffer::operator >> (short &nT)
{
    memcpy(&nT, m_pBuf + m_nIndex, 2);
    m_nIndex += 2;
    return *this;
}

inline CBuffer &CBuffer::operator << (const unsigned short nT)
{
    memcpy(m_pBuf + m_nIndex, &nT, 2);
    m_nIndex += 2;
    return *this;
}

inline CBuffer &CBuffer::operator >> (unsigned short &nT)
{
    memcpy(&nT, m_pBuf + m_nIndex, 2);
    m_nIndex += 2;
    return *this;
}

inline CBuffer &CBuffer::operator << (const int nT)
{
    memcpy(m_pBuf + m_nIndex, &nT, 4);
    m_nIndex += 4;
    return *this;
}

inline CBuffer &CBuffer::operator >> (int &nT)
{
    memcpy(&nT, m_pBuf + m_nIndex, 4);
    m_nIndex += 4;
    return *this;
}

inline CBuffer &CBuffer::operator << (const unsigned int nT)
{
    memcpy(m_pBuf + m_nIndex, &nT, 4);
    m_nIndex += 4;
    return *this;
}

inline CBuffer &CBuffer::operator >> (unsigned int &nT)
{
    memcpy(&nT, m_pBuf + m_nIndex, 4);
    m_nIndex += 4;
    return *this;
}

inline CBuffer &CBuffer::operator << (const long nT)
{
    memcpy(m_pBuf + m_nIndex, &nT, 4);
    m_nIndex += 4;
    return *this;
}

inline CBuffer &CBuffer::operator >> (long &nT)
{
    memcpy(&nT, m_pBuf + m_nIndex, 4);
    m_nIndex += 4;
    return *this;
}

inline CBuffer &CBuffer::operator << (const unsigned long nT)
{
    memcpy(m_pBuf + m_nIndex, &nT, 4);
    m_nIndex += 4;
    return *this;
}

inline CBuffer &CBuffer::operator >> (unsigned long &nT)
{
    memcpy(&nT, m_pBuf + m_nIndex, 4);
    m_nIndex += 4;
    return *this;
}

inline CBuffer &CBuffer::operator << (const long long nT)
{
    memcpy(m_pBuf + m_nIndex, &nT, 8);
    m_nIndex += 8;
    return *this;
}

inline CBuffer &CBuffer::operator >> (long long &nT)
{
    memcpy(&nT, m_pBuf + m_nIndex, 8);
    m_nIndex += 8;
    return *this;
}

inline CBuffer &CBuffer::operator << (const unsigned long long nT)
{
    memcpy(m_pBuf + m_nIndex, &nT, 8);
    m_nIndex += 8;
    return *this;
}

inline CBuffer &CBuffer::operator  >> (unsigned long long &nT)
{
    memcpy(&nT, m_pBuf + m_nIndex, 8);
    m_nIndex += 8;
    return *this;
}

inline CBuffer &CBuffer::operator << (const char *pBuf)
{
    int nLen = (int)strlen(pBuf);
    if (nLen > 0 && nLen <= 0xFFFFFF)
    {
        *this << nLen;
        memcpy(m_pBuf + m_nIndex, pBuf, nLen);
        m_nIndex += nLen;
    }
    else
    {
        nLen = 0;
        *this << nLen;
    }
    return *this;
}

inline CBuffer &CBuffer::operator >> (char *&pBuf)
{
    int nLen = 0;
    *this >> nLen;
    if (nLen > 0 && nLen <= 0xFFFFFF)
    {
        if (pBuf == NULL)
        {
            pBuf = new char[nLen + 1];
        }
        memcpy(pBuf, m_pBuf + m_nIndex, nLen);
        pBuf[nLen] = 0;
        m_nIndex += nLen;
    }
    return *this;
}

inline CBuffer &CBuffer::operator << (const unsigned char *pBuf)
{
    int nLen = (int)strlen((const char *)pBuf);
    if (nLen > 0 && nLen <= 0xFFFFFF)
    {
        *this << nLen;
        memcpy(m_pBuf + m_nIndex, pBuf, nLen);
        m_nIndex += nLen;
    }
    else
    {
        nLen = 0;
        *this << nLen;
    }
    return *this;
}

inline CBuffer &CBuffer::operator >> (unsigned char *&pBuf)
{
    int nLen = 0;
    *this >> nLen;
    if (nLen > 0 && nLen <= 0xFFFFFF)
    {
        if (pBuf == NULL)
        {
            pBuf = new unsigned char[nLen + 1];
        }
        memcpy(pBuf, m_pBuf + m_nIndex, nLen);
        pBuf[nLen] = 0;
        m_nIndex += nLen;
    }
    return *this;
}

inline CBuffer &CBuffer::operator << (const float v)
{
    memcpy(m_pBuf + m_nIndex, &v, 4);
    m_nIndex += 4;
    return *this;
}

inline CBuffer &CBuffer::operator >> (float &v)
{
    memcpy(&v, m_pBuf + m_nIndex, 4);
    m_nIndex += 4;
    return *this;
}

inline CBuffer &CBuffer::operator << (const double v)
{
    memcpy(m_pBuf + m_nIndex, &v, 8);
    m_nIndex += 8;
    return *this;
}

inline CBuffer &CBuffer::operator >> (double &v)
{
    memcpy(&v, m_pBuf + m_nIndex, 8);
    m_nIndex += 8;
    return *this;
}

inline CBuffer &CBuffer::operator << (const std::string &v)
{
    int nLen = (int)v.size();
    *this << nLen;
    memcpy(m_pBuf + m_nIndex, v.c_str(), nLen);
    m_nIndex += nLen;

    return *this;
}

inline CBuffer &CBuffer::operator >> (std::string &v)
{
    int nLen;
    *this >> nLen;
    if (nLen > 0)
    {
        char *pBuf = new char[nLen + 1];
        memcpy(pBuf, m_pBuf + m_nIndex, nLen);
        m_nIndex += nLen;
        pBuf[nLen] = 0;
        v = pBuf;
        delete[] pBuf;
    }
    return *this;
}

inline void	CBuffer::Dump()
{
    for (int i = 0; i < m_nIndex; i++)
    {
        printf("%02X", (unsigned char)m_pBuf[i]);
    }
    printf("\n");
}

inline int CBuffer::WriteFile(const char *lpszFile)
{
    FILE *fp = fopen(lpszFile, "w+b");
    if (fp != NULL)
    {
        fwrite(Data(), 1, Size(), fp);
        fclose(fp);
        return Size();
    }
    return 0;
};

inline int CBuffer::ReadFile(const char *lpszFile)
{
    FILE *fp = fopen(lpszFile, "r+b");
    if (fp != NULL)
    {
        if (m_nSize > 0)
        {
            delete m_pBuf;
        }
        fseek(fp, 0, SEEK_END);
        int nLength = ftell(fp);
        fseek(fp, 0, SEEK_SET);
        m_pBuf = new char[nLength];
        fread(m_pBuf, 1, nLength, fp);
        fclose(fp);
        m_nIndex = 0;
        return nLength;
    }
    return 0;
};

#endif
